<template>
  <div class="img-upload-zore">
    <div
      v-for="(file, index) in fileList"
      :key="file.uid + '_' + index"
      v-loading="file.status === 'uploading'"
      class="img-view"
    >
      <el-image
        class="img-item"
        :src="transImgsUrl(file)"
        fit="cover"
        :preview-src-list="fileList.map(transImgsUrl)"
        :initial-index="index"
      />
      <span class="img-actions">
        <span v-if="!disabled" class="img-icon" @click="handleRemove(index)">
          <el-icon><Delete /></el-icon>
        </span>
      </span>

      <div v-if="file.status === 'fail'" class="err-status-tips">
        <span>上传失败，请重试</span>
      </div>
    </div>
    <UploadFile
      v-show="showUpload"
      ref="uploadIns"
      v-model:file-list="fileList"
      :show-file-list="false"
      :disabled="disabled"
      multiple
      :accept="['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp']"
    >
      <div class="img-view">
        <el-icon size="30"><Plus /></el-icon>
      </div>
    </UploadFile>
  </div>
</template>

<script name="ImageUpload" lang="ts" setup>
  import { computed, ref, watchEffect, type PropType, watch } from 'vue';
  import { Delete, Plus } from '@element-plus/icons-vue';
  import UploadFile from './upload.vue';

  const props = defineProps({
    modelValue: {
      type: [String, Array] as PropType<string[] | string>,
      default: () => undefined
    },
    multiple: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    limit: {
      type: Number,
      default: undefined
    }
  });

  const emits = defineEmits<{
    (event: 'update:modelValue', value?: string[] | string): void;
    (event: 'fileChange', files: any): void;
  }>();

  const fileList = ref<Array<IFileType>>([]);

  const uploadIns = ref<typeof UploadFile>();

  const showUpload = computed(() => {
    if (!props.multiple) {
      return fileList.value.length < 1;
    } else {
      if (props.limit !== undefined) {
        return fileList.value.length < props.limit;
      }
    }
    return true;
  });

  const handleRemove = (index: number) => {
    fileList.value.splice(index, 1);
  };

  const transImgsUrl = (file: IFileType) => {
    if (file.isRWrite) {
      return file.url as string;
    }
    return window.URL.createObjectURL(file.raw!);
  };

  defineExpose({
    async submit(prams: any) {
      try {
        if (fileList.value.length == 0) {
          emits('update:modelValue', undefined);
          return Promise.resolve();
        }
        const urls = await uploadIns.value?.submit(prams);
        if (props.multiple) {
          emits('update:modelValue', urls);
          return Promise.resolve(urls);
        } else {
          emits('update:modelValue', urls[0]);
          return Promise.resolve(urls[0]);
        }
      } catch (error) {
        return Promise.reject(error);
      }
    }
  });

  watchEffect(() => {
    if (!props.modelValue) {
      fileList.value = [];
    } else if (Array.isArray(props.modelValue)) {
      fileList.value = props.modelValue.map((item) => ({
        name: item,
        url: item,
        isRWrite: true
      }));
    } else {
      fileList.value = [
        {
          name: props.modelValue,
          url: props.modelValue,
          isRWrite: true
        }
      ];
    }
  });

  watch(fileList, (val) => {
    emits('fileChange', val);
  });
</script>

<style lang="less" scoped>
  .img-upload-zore {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
  }
  .img-item {
    width: 100%;
    height: 100%;
  }
  .img-view {
    width: 150px;
    height: 150px;
    margin-right: 12px;
    margin-bottom: 12px;
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
    display: flex;
    justify-content: center;
    align-items: center;
    &:hover {
      .img-actions {
        opacity: 1;
      }
    }
    .img-actions {
      position: absolute;
      z-index: 2;
      width: 100%;
      height: 20%;
      left: 0;
      bottom: 0;
      cursor: default;
      display: inline-flex;
      justify-content: center;
      align-items: center;
      color: #fff;
      opacity: 0;
      font-size: 20px;
      background-color: var(--el-overlay-color-lighter);
      transition: opacity var(--el-transition-duration);

      .img-icon {
        cursor: pointer;
      }
    }
  }

  .err-status-tips {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background-color: var(--el-overlay-color-lighter);
    transition: opacity var(--el-transition-duration);
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 12px;
    color: var(--el-color-danger);
  }
</style>
